package com.campus.help.controller;

import com.campus.help.common.Result;
import com.campus.help.dto.UpdateUserInfoDTO;
import com.campus.help.dto.WechatLoginDTO;
import com.campus.help.entity.Student;
import com.campus.help.service.AuthService;
// import com.campus.help.service.SchoolService; // 暂时注释，等实现后再开启
import com.campus.help.utils.JwtUtils;
import com.campus.help.utils.RedisUtils;
// Swagger注解已移除，如需要可以添加swagger依赖
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 授权登录控制器
 *
 * @author campus-help
 * @since 2025-09-18
 */
@Slf4j
@RestController
@RequestMapping("/auth")
@Validated
public class AuthController {

    @Autowired
    private AuthService authService;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private RedisUtils redisUtils;

    // @Autowired
    // private SchoolService schoolService; // 暂时注释，等实现后再开启

    /**
     * 微信小程序登录
     */
    @PostMapping("/wechat/login")
    public Result<AuthService.LoginResult> wechatLogin(@Valid @RequestBody WechatLoginDTO loginDTO, HttpServletRequest request) {
        String clientIP = getClientIP(request);
        log.info("微信登录请求，IP: {}, code: {}", clientIP, loginDTO.getCode());

        try {
            if (loginDTO == null || !StringUtils.hasText(loginDTO.getCode())) {
                return Result.error("登录凭证不能为空");
            }

            // 检查登录频率限制
            String loginLimitKey = "login:limit:" + clientIP;
            String loginCount = redisUtils.get(loginLimitKey, String.class);
            if (loginCount != null && Integer.parseInt(loginCount) > 10) {
                return Result.error("登录次数过多，请稍后再试");
            }

            AuthService.LoginResult loginResult = authService.wechatLogin(loginDTO.getCode());

            // 记录登录成功
            log.info("用户登录成功，studentId: {}, IP: {}", loginResult.getStudent().getId(), clientIP);

            // 重置登录限制计数
            redisUtils.delete(loginLimitKey);

            return Result.success("登录成功", loginResult);
        } catch (Exception e) {
            log.error("微信登录失败，IP: {}, error: {}", clientIP, e.getMessage(), e);

            // 增加登录失败计数
            String loginLimitKey = "login:limit:" + clientIP;
            String loginCount = redisUtils.get(loginLimitKey, String.class);
            int count = loginCount == null ? 1 : Integer.parseInt(loginCount) + 1;
            redisUtils.set(loginLimitKey, String.valueOf(count), 300, java.util.concurrent.TimeUnit.SECONDS); // 5分钟过期

            return Result.error("登录失败: " + e.getMessage());
        }
    }


    /**
     * 简化更新用户信息（适配新版微信头像昵称组件）
     */
    @PostMapping("/user/update-simple")
    public Result<Student> updateUserInfoSimple(
            @RequestBody com.campus.help.dto.UpdateUserSimpleDTO updateDTO,
            HttpServletRequest request) {
        try {
            // 从token中获取学生ID
            String token = getTokenFromRequest(request);
            Long studentId = jwtUtils.getStudentIdFromToken(token);

            log.info("简化更新用户信息请求，studentId: {}, nickname: {}, avatarUrl: {}", 
                    studentId, updateDTO.getNickname(), updateDTO.getAvatarUrl());

            Student student = authService.updateUserInfoSimple(
                    studentId, 
                    updateDTO.getNickname(), 
                    updateDTO.getAvatarUrl(), 
                    updateDTO.getSchoolId(), 
                    updateDTO.getPhone(), 
                    updateDTO.getQq(), 
                    updateDTO.getWechat(), 
                    updateDTO.getEmail()
            );

            log.info("用户信息更新成功，studentId: {}", studentId);
            return Result.success("用户信息更新成功", student);
        } catch (Exception e) {
            log.error("更新用户信息失败", e);
            return Result.error("更新用户信息失败: " + e.getMessage());
        }
    }

    /**
     * 更新用户信息（使用加密数据）
     */
    @PostMapping("/user/update")
    public Result<Student> updateUserInfo(@Valid @RequestBody UpdateUserInfoDTO updateDTO, HttpServletRequest request) {
        try {
            if (updateDTO == null || !StringUtils.hasText(updateDTO.getEncryptedData())) {
                return Result.error("加密数据不能为空");
            }

            // 从token中获取学生ID
            String token = getTokenFromRequest(request);
            Long studentId = jwtUtils.getStudentIdFromToken(token);

            log.info("更新用户信息请求，studentId: {}", studentId);

            Student student = authService.updateUserInfo(studentId,
                    updateDTO.getEncryptedData(),
                    updateDTO.getSessionKey(),
                    updateDTO.getIv(),
                    updateDTO.getSchoolId(),
                    updateDTO.getPhone(),
                    updateDTO.getQq(),
                    updateDTO.getWechat(),
                    updateDTO.getEmail());

            // 如果学生有学校ID，获取学校名称
            if (student.getSchoolId() != null) {
                try {
                    // 暂时注释掉，等SchoolService实现后再开启
                    // com.campus.help.vo.SchoolVO school = schoolService.getSchoolById(student.getSchoolId());
                    // student.setSchoolName(school.getSchoolName());
                } catch (Exception e) {
                    log.warn("获取学校信息失败: schoolId={}, error={}", student.getSchoolId(), e.getMessage());
                }
            }

            log.info("用户信息更新成功，studentId: {}", studentId);
            return Result.success("用户信息更新成功", student);
        } catch (Exception e) {
            log.error("更新用户信息失败", e);
            return Result.error("更新用户信息失败: " + e.getMessage());
        }
    }

    /**
     * 更新用户所属学校
     */
    @PostMapping("/user/update-school")
    public Result<Student> updateUserSchool(
            @Valid @RequestBody com.campus.help.dto.UpdateSchoolDTO updateSchoolDTO,
            HttpServletRequest request) {
        try {
            // 从token中获取学生ID
            String token = getTokenFromRequest(request);
            Long studentId = jwtUtils.getStudentIdFromToken(token);

            Long schoolId = updateSchoolDTO.getSchoolId();
            log.info("更新用户学校请求，studentId: {}, schoolId: {}", studentId, schoolId);

            // 调用服务更新学校ID
            Student student = authService.updateUserSchool(studentId, schoolId);

            log.info("用户学校更新成功，studentId: {}, schoolId: {}", studentId, schoolId);
            return Result.success("学校设置成功", student);
        } catch (Exception e) {
            log.error("更新用户学校失败", e);
            return Result.error("更新学校失败: " + e.getMessage());
        }
    }

    /**
     * 获取当前用户信息
     */
    @GetMapping("/user/info")
    public Result<Student> getCurrentUser(HttpServletRequest request) {
        try {
            String token = getTokenFromRequest(request);
            Student student = authService.validateToken(token);

            // 如果学生有学校ID，获取学校名称
            if (student.getSchoolId() != null) {
                try {
                    // 暂时注释掉，等SchoolService实现后再开启
                    // com.campus.help.vo.SchoolVO school = schoolService.getSchoolById(student.getSchoolId());
                    // student.setSchoolName(school.getSchoolName());
                } catch (Exception e) {
                    log.warn("获取学校信息失败: schoolId={}, error={}", student.getSchoolId(), e.getMessage());
                }
            }

            return Result.success(student);
        } catch (Exception e) {
            log.error("获取用户信息失败", e);
            return Result.error("获取用户信息失败: " + e.getMessage());
        }
    }

    /**
     * 获取用户统计信息
     */
    @GetMapping("/user/stats")
    public Result<java.util.Map<String, Object>> getUserStats(HttpServletRequest request) {
        try {
            String token = getTokenFromRequest(request);
            Long studentId = jwtUtils.getStudentIdFromToken(token);

            log.info("获取用户统计信息: studentId={}", studentId);

            // 创建统计数据
            java.util.Map<String, Object> stats = new java.util.HashMap<>();

            // 获取用户信用分（从Student表）
            Student student = authService.validateToken(token);
            stats.put("creditScore", student.getCreditScore() != null ? student.getCreditScore() : 100);

            // 获取发布数（劳务 + 二手）
            // TODO: 实际应该查询数据库
            stats.put("publishCount", 0);

            // 获取申请数
            // TODO: 实际应该查询数据库
            stats.put("applicationCount", 0);

            // 获取完成数
            // TODO: 实际应该查询数据库
            stats.put("completedCount", 0);

            log.info("用户统计信息: {}", stats);
            return Result.success(stats);
        } catch (Exception e) {
            log.error("获取用户统计信息失败", e);
            return Result.error("获取用户统计信息失败: " + e.getMessage());
        }
    }

    /**
     * 管理员获取用户信息
     */
    @GetMapping("/admin/info")
    public Result<Map<String, Object>> getAdminInfo(HttpServletRequest request) {
        try {
            String token = getTokenFromRequest(request);

            // 验证管理员token（暂时简化验证）
            String redisKey = "admin:token:admin";
            String storedToken = redisUtils.get(redisKey, String.class);
            if (!token.equals(storedToken)) {
                return Result.error("管理员token无效");
            }

            String username = "admin"; // 临时固定用户名

            Map<String, Object> adminInfo = new HashMap<>();
            adminInfo.put("roles", new String[]{"admin"});
            adminInfo.put("introduction", "我是超级管理员");
            adminInfo.put("avatar", "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
            adminInfo.put("name", "Super Admin");
            adminInfo.put("username", username);

            return Result.success(adminInfo);
        } catch (Exception e) {
            log.error("获取管理员信息失败", e);
            return Result.error("获取管理员信息失败: " + e.getMessage());
        }
    }

    /**
     * 获取用户总数
     */
    @GetMapping("/users/count")
    public Result<Long> getTotalUsersCount() {
        try {
            Long totalCount = authService.getTotalUsersCount();
            return Result.success(totalCount);
        } catch (Exception e) {
            log.error("获取用户总数失败", e);
            return Result.error("获取用户总数失败: " + e.getMessage());
        }
    }

    /**
     * 获取用户列表（管理员接口）
     */
    @GetMapping("/users/list")
    public Result<Map<String, Object>> getUsersList(
            @RequestParam(defaultValue = "1") @Min(1) Integer page,
            @RequestParam(defaultValue = "20") @Min(1) Integer limit,
            @RequestParam(required = false) String keyword,
            @RequestParam(required = false) String status,
            @RequestParam(required = false) String userType,
            @RequestParam(required = false) String verifyStatus) {
        try {
            // 暂时返回模拟数据，实际应该调用authService
            Map<String, Object> result = new HashMap<>();
            result.put("total", 100);
            result.put("page", page);
            result.put("limit", limit);
            result.put("list", new java.util.ArrayList<>());

            log.info("获取用户列表，page: {}, limit: {}, keyword: {}", page, limit, keyword);
            return Result.success(result);
        } catch (Exception e) {
            log.error("获取用户列表失败", e);
            return Result.error("获取用户列表失败: " + e.getMessage());
        }
    }

    /**
     * 更新用户状态（管理员接口）
     */
    @PutMapping("/users/{userId}/status")
    public Result<String> updateUserStatus(
            @PathVariable @NotNull Long userId,
            @RequestParam @NotNull String status,
            HttpServletRequest request) {
        try {
            String token = getTokenFromRequest(request);

            // 简化的管理员权限验证
            String redisKey = "admin:token:admin";
            String storedToken = redisUtils.get(redisKey, String.class);
            if (!token.equals(storedToken)) {
                return Result.error("权限不足");
            }

            // 暂时只记录日志，实际应该更新数据库
            log.info("管理员更新用户状态，userId: {}, status: {}", userId, status);

            return Result.success("用户状态更新成功");
        } catch (Exception e) {
            log.error("更新用户状态失败", e);
            return Result.error("更新用户状态失败: " + e.getMessage());
        }
    }

    /**
     * 审核学生认证（管理员接口）
     */
    @PutMapping("/users/{userId}/verify")
    public Result<String> verifyStudent(
            @PathVariable @NotNull Long userId,
            @RequestParam @NotNull String verifyStatus,
            @RequestParam(required = false) String rejectReason,
            HttpServletRequest request) {
        try {
            String token = getTokenFromRequest(request);

            // 简化的管理员权限验证
            String redisKey = "admin:token:admin";
            String storedToken = redisUtils.get(redisKey, String.class);
            if (!token.equals(storedToken)) {
                return Result.error("权限不足");
            }

            if ("REJECTED".equals(verifyStatus) && !StringUtils.hasText(rejectReason)) {
                return Result.error("拒绝时必须提供拒绝原因");
            }

            // 暂时只记录日志，实际应该更新数据库
            log.info("管理员审核学生认证，userId: {}, verifyStatus: {}, rejectReason: {}",
                    userId, verifyStatus, rejectReason);

            return Result.success("学生认证审核完成");
        } catch (Exception e) {
            log.error("审核学生认证失败", e);
            return Result.error("审核学生认证失败: " + e.getMessage());
        }
    }

    /**
     * 获取用户统计信息
     */
    @GetMapping("/users/statistics")
    public Result<Map<String, Object>> getUserStatistics() {
        try {
            // 暂时返回模拟数据
            Map<String, Object> statistics = new HashMap<>();
            statistics.put("totalUsers", 1286);
            statistics.put("activeUsers", 856);
            statistics.put("newUsersToday", 23);
            statistics.put("verifiedUsers", 1050);
            statistics.put("pendingVerification", 45);

            return Result.success(statistics);
        } catch (Exception e) {
            log.error("获取用户统计信息失败", e);
            return Result.error("获取用户统计信息失败: " + e.getMessage());
        }
    }

    /**
     * 获取最近登录用户
     */
    @GetMapping("/users/recent-login")
    public Result<List<Map<String, Object>>> getRecentLoginUsers(@RequestParam(defaultValue = "10") @Min(1) Integer limit) {
        try {
            // 暂时返回模拟数据
            List<Map<String, Object>> recentUsers = new java.util.ArrayList<>();
            for (int i = 1; i <= Math.min(limit, 5); i++) {
                Map<String, Object> user = new HashMap<>();
                user.put("id", i);
                user.put("name", "用户" + i);
                user.put("lastLoginTime", LocalDateTime.now().minusHours(i));
                recentUsers.add(user);
            }

            return Result.success(recentUsers);
        } catch (Exception e) {
            log.error("获取最近登录用户失败", e);
            return Result.error("获取最近登录用户失败: " + e.getMessage());
        }
    }

    /**
     * 刷新token
     */
    @PostMapping("/refresh")
    public Result<String> refreshToken(HttpServletRequest request) {
        try {
            String token = getTokenFromRequest(request);
            Student student = authService.validateToken(token);
            String newToken = authService.generateToken(student);
            return Result.success("Token刷新成功", newToken);
        } catch (Exception e) {
            log.error("刷新Token失败", e);
            return Result.error("刷新Token失败: " + e.getMessage());
        }
    }

    /**
     * 用户退出登录
     */
    @PostMapping("/logout")
    public Result<String> logout(HttpServletRequest request) {
        try {
            String token = getTokenFromRequest(request);
            Long studentId = jwtUtils.getStudentIdFromToken(token);

            // 从Redis中删除token
            String redisKey = "student:token:" + studentId;
            redisUtils.delete(redisKey);
            log.info("用户退出登录，studentId: {}", studentId);

            return Result.success("退出登录成功");
        } catch (Exception e) {
            log.error("退出登录失败", e);
            return Result.error("退出登录失败: " + e.getMessage());
        }
    }

    /**
     * 管理员退出登录
     */
    @PostMapping("/admin/logout")
    public Result<String> adminLogout(HttpServletRequest request) {
        try {
            // String token = getTokenFromRequest(request); // 暂时不需要验证token
            String username = "admin"; // 临时固定用户名

            // 从Redis中删除token
            String redisKey = "admin:token:" + username;
            redisUtils.delete(redisKey);
            log.info("管理员退出登录，username: {}", username);

            return Result.success("退出登录成功");
        } catch (Exception e) {
            log.error("管理员退出登录失败", e);
            return Result.error("退出登录失败: " + e.getMessage());
        }
    }

    /**
     * 密码重置（发送验证码）
     */
    @PostMapping("/password/reset/send-code")
    public Result<String> sendResetCode(@RequestParam @NotNull String phone, HttpServletRequest request) {
        String clientIP = getClientIP(request);

        try {
            // 检查发送频率限制
            String limitKey = "reset:code:limit:" + phone;
            String limitCount = redisUtils.get(limitKey, String.class);
            if (limitCount != null && Integer.parseInt(limitCount) > 5) {
                return Result.error("验证码发送次数过多，请稍后再试");
            }

            // 生成6位数字验证码
            String code = String.format("%06d", (int) (Math.random() * 1000000));

            // 存储验证码，5分钟过期
            String codeKey = "reset:code:" + phone;
            redisUtils.set(codeKey, code, 300, java.util.concurrent.TimeUnit.SECONDS);

            // 增加发送计数
            String countStr = redisUtils.get(limitKey, String.class);
            int count = countStr == null ? 1 : Integer.parseInt(countStr) + 1;
            redisUtils.set(limitKey, String.valueOf(count), 3600, java.util.concurrent.TimeUnit.SECONDS); // 1小时过期

            // 这里应该调用短信发送服务
            log.info("发送密码重置验证码，phone: {}, code: {}, IP: {}", phone, code, clientIP);

            return Result.success("验证码发送成功");
        } catch (Exception e) {
            log.error("发送密码重置验证码失败，phone: {}, IP: {}", phone, clientIP, e);
            return Result.error("发送验证码失败: " + e.getMessage());
        }
    }

    /**
     * 密码重置（验证码验证）
     */
    @PostMapping("/password/reset/verify")
    public Result<String> resetPassword(
            @RequestParam @NotNull String phone,
            @RequestParam @NotNull String code,
            @RequestParam @NotNull String newPassword,
            HttpServletRequest request) {
        String clientIP = getClientIP(request);

        try {
            // 验证验证码
            String codeKey = "reset:code:" + phone;
            String storedCode = redisUtils.get(codeKey, String.class);

            if (storedCode == null) {
                return Result.error("验证码已过期");
            }

            if (!storedCode.equals(code)) {
                return Result.error("验证码错误");
            }

            // 暂时只记录日志，实际应该重置密码
            log.info("重置密码，phone: {}", phone);

            // 删除验证码
            redisUtils.delete(codeKey);

            log.info("密码重置成功，phone: {}, IP: {}", phone, clientIP);
            return Result.success("密码重置成功");
        } catch (Exception e) {
            log.error("密码重置失败，phone: {}, IP: {}", phone, clientIP, e);
            return Result.error("密码重置失败: " + e.getMessage());
        }
    }

    /**
     * 绑定手机号
     */
    @PostMapping("/bind/phone")
    public Result<String> bindPhone(
            @RequestParam @NotNull String phone,
            @RequestParam @NotNull String code,
            HttpServletRequest request) {
        try {
            String token = getTokenFromRequest(request);
            Long studentId = jwtUtils.getStudentIdFromToken(token);

            // 验证短信验证码
            String codeKey = "bind:phone:code:" + phone;
            String storedCode = redisUtils.get(codeKey, String.class);

            if (storedCode == null) {
                return Result.error("验证码已过期");
            }

            if (!storedCode.equals(code)) {
                return Result.error("验证码错误");
            }

            // 暂时只记录日志，实际应该绑定手机号
            log.info("绑定手机号，studentId: {}, phone: {}", studentId, phone);

            // 删除验证码
            redisUtils.delete(codeKey);

            log.info("手机号绑定成功，studentId: {}, phone: {}", studentId, phone);
            return Result.success("手机号绑定成功");
        } catch (Exception e) {
            log.error("手机号绑定失败", e);
            return Result.error("手机号绑定失败: " + e.getMessage());
        }
    }

    /**
     * 系统健康检查
     */
    @GetMapping("/health")
    public Result<Map<String, Object>> healthCheck() {
        Map<String, Object> health = new HashMap<>();

        try {
            // 检查Redis连接
            redisUtils.set("test:health", "ok", 10, java.util.concurrent.TimeUnit.SECONDS);
            String redisResult = redisUtils.get("test:health", String.class);
            health.put("redis", "ok".equals(redisResult) ? "UP" : "DOWN");

            // 检查数据库连接
            Long userCount = authService.getTotalUsersCount();
            health.put("database", userCount != null ? "UP" : "DOWN");

            // 系统信息
            health.put("timestamp", LocalDateTime.now());
            health.put("status", "UP");
            health.put("version", "1.0.0");

            return Result.success(health);
        } catch (Exception e) {
            log.error("健康检查失败", e);
            health.put("status", "DOWN");
            health.put("error", e.getMessage());
            return Result.error("系统健康检查失败");
        }
    }

    /**
     * Redis健康检查
     */
    @GetMapping("/health/redis")
    public Result<String> checkRedisHealth() {
        try {
            // 测试Redis连接
            redisUtils.set("test:health", "ok", 10, java.util.concurrent.TimeUnit.SECONDS);
            String result = redisUtils.get("test:health", String.class);
            if ("ok".equals(result)) {
                return Result.success("Redis连接正常");
            } else {
                return Result.error("Redis连接异常");
            }
        } catch (Exception e) {
            log.error("Redis健康检查失败", e);
            return Result.error("Redis连接失败: " + e.getMessage());
        }
    }

    /**
     * 获取在线用户数
     */
    @GetMapping("/online-users")
    public Result<Map<String, Object>> getOnlineUsers() {
        try {
            Map<String, Object> onlineInfo = new HashMap<>();

            // 暂时返回模拟数据，实际应该从Redis扫描token
            // 注意：Redis keys操作在生产环境中需要谨慎使用
            onlineInfo.put("onlineStudents", 28);
            onlineInfo.put("onlineAdmins", 3);
            onlineInfo.put("totalOnline", 31);
            onlineInfo.put("timestamp", LocalDateTime.now());

            return Result.success(onlineInfo);
        } catch (Exception e) {
            log.error("获取在线用户数失败", e);
            return Result.error("获取在线用户数失败: " + e.getMessage());
        }
    }

    /**
     * 清理过期token（管理员接口）
     */
    @PostMapping("/admin/clean-expired-tokens")
    public Result<Map<String, Object>> cleanExpiredTokens(HttpServletRequest request) {
        try {
            String token = getTokenFromRequest(request);

            // 简化的管理员权限验证
            String redisKey = "admin:token:admin";
            String storedToken = redisUtils.get(redisKey, String.class);
            if (!token.equals(storedToken)) {
                return Result.error("权限不足");
            }

            Map<String, Object> result = new HashMap<>();
            int cleanedCount = 0;

            // 暂时返回模拟数据，实际应该扫描和清理Redis中的过期token
            cleanedCount = 5; // 模拟清理了5个过期token

            result.put("cleanedTokens", cleanedCount);
            result.put("timestamp", LocalDateTime.now());

            log.info("管理员清理过期token，清理数量: {}", cleanedCount);
            return Result.success("过期token清理完成", result);
        } catch (Exception e) {
            log.error("清理过期token失败", e);
            return Result.error("清理过期token失败: " + e.getMessage());
        }
    }

    // ==================== 私有工具方法 ====================

    /**
     * 从请求中获取token
     */
    private String getTokenFromRequest(HttpServletRequest request) {
        String authorization = request.getHeader("Authorization");
        if (authorization != null && authorization.startsWith("Bearer ")) {
            return authorization.substring(7);
        }

        // 也支持从X-Token头获取
        String xToken = request.getHeader("X-Token");
        if (StringUtils.hasText(xToken)) {
            return xToken;
        }

        throw new RuntimeException("Token不能为空");
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIP(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        String xRealIP = request.getHeader("X-Real-IP");

        if (StringUtils.hasText(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }

        if (StringUtils.hasText(xRealIP)) {
            return xRealIP;
        }

        return request.getRemoteAddr();
    }

    // 验证请求参数的工具方法已移除，使用Spring Validation注解代替
}
